package com.years.ground_station.widget.scrollview;

import android.content.Context;
import android.os.Build;
import android.support.v4.view.ViewCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ScrollView;

/**
 * Created by Administrator on 2015/12/5 0005.
 */
public class ElasticScrollView extends ScrollView {

    private static final float ELASTICITY_COEFFICIENT=0.25f;  //滚动系数, 视图滚动距离与手指滑动距离的比值
    private static final int NO_OVERSCROLL_STATE = 0;          //无弹性滚动状态
    private static final int TOP_OVERSCROLL_STATE = 1;         //上方弹性滚动状态
    private static final int BOTTOM_OVERSCROLL_STATE = 2;      //下方弹性滚动状态
    private static final int OVERSCROLL_MAX_HEIGHT = 1200;     //滚动最大高度,超过此高度不再滚动
    private static final int INVALID_POINTER = -1;             //无当前活动指针的哨兵值
    private static final int TRIGGER_HEIGHT = 120;             //触发事件的高度默认阀值

    private int overScrollSate;                                //弹性滚动状态
    private boolean mIsUseOverScroll = true;                   //属性标志位:是否可以弹性滚动
    private boolean isRecord;                                  //是否标记可以滚动
    private ElasticScrollViewLayout mContentLayout;            //自定义的弹性滚动视图
    private OverScrollListener mOverScrollListener;            //OverScroll监听器
    private OverScrollTinyListener mOverScrollTinyListener;    //OverScroll细致监听器
    private OnScrollListener mScrollListener;                  //Scroll细致监听器
    private float mLastMotionY;                                //最新一次的手指触摸位置
    private int overScrollDistance;                            //弹性滚动总距离,向下为负，向上为正
    private int mActivePointerId = INVALID_POINTER;            //按在屏幕上的手指的id
    private boolean isOnTouch;                                 //是否触摸
    private boolean isInertance;                               //是否具有惯性
    private boolean mIsUseInertance = true;                    //是否使用惯性
    private boolean mIsBanQuickScroll;                         //是否禁用快速滚动
    private int inertanceY;                                    //惯性距离(与滑动速率有关)
    private int mOverScrollTrigger = TRIGGER_HEIGHT;           //触发事件的高度阀值，最小值为30

    public ElasticScrollView(Context context) {
       this(context,null);
    }

    public ElasticScrollView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ElasticScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initScrollView();
    }
    private void initScrollView(){
        //设置滚动无阴影( API Level 9 )
        if(Build.VERSION.SDK_INT >= 9){
            setOverScrollMode(View.OVER_SCROLL_NEVER);
        }else{
            ViewCompat.setOverScrollMode(this, ViewCompat.OVER_SCROLL_NEVER);
        }
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        // 如果禁用，不做任何处理
        if(!mIsUseOverScroll){
            return super.onInterceptTouchEvent(ev);
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (isOverScrolled()) {
                    isRecord = true;
                    // Remember where the motion event started
                    mLastMotionY = (int) ev.getY();

                    mActivePointerId = ev.getPointerId(0);
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if(isRecord && Math.abs(ev.getY() - mLastMotionY) > 20){
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
                if(isRecord){
                    isRecord = false;
                }
        }
        return super.onInterceptTouchEvent(ev);
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        isOnTouch = true;
        if(ev.getAction() == MotionEvent.ACTION_UP || ev.getAction() == MotionEvent.ACTION_CANCEL){
            if(mOverScrollTinyListener != null){
                mOverScrollTinyListener.scrollLoosen();
            }
            isOnTouch = false;
        }

        // 如果禁用，不做任何处理
        if(!mIsUseOverScroll){
            return super.onTouchEvent(ev);
        }

        if(!isOverScrolled()){
            mLastMotionY = (int) ev.getY();
            return super.onTouchEvent(ev);
        }

        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mActivePointerId = ev.getPointerId(0);
                mLastMotionY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_POINTER_DOWN:
                final int index = ev.getActionIndex();
                mLastMotionY = (int) ev.getY(index);
                mActivePointerId = ev.getPointerId(index);
                break;
            case MotionEvent.ACTION_POINTER_UP:
                onSecondaryPointerUp(ev);
                if(mActivePointerId != INVALID_POINTER){
                    mLastMotionY = (int) ev.getY(ev.findPointerIndex(mActivePointerId));
                }
                break;
            case MotionEvent.ACTION_MOVE:
                if (isRecord) {
                    final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
                    if (activePointerIndex == -1) {
                        break;
                    }


                    final float y = ev.getY(activePointerIndex);
                    // 滚动距离
                    int deltaY = (int) (mLastMotionY - y);
                    // 记录新的触摸位置
                    mLastMotionY = y;

                    if(Math.abs(overScrollDistance) >= OVERSCROLL_MAX_HEIGHT && overScrollDistance * deltaY > 0){
                        deltaY = 0;
                    }

                    //如果滚动到ScrollView自身滚动边界，直接调用自身滚动
                    if(overScrollDistance *(overScrollDistance + deltaY) < 0){
                        mContentLayout.smoothScrollToNormal();
                        overScrollDistance = 0;
                        break;
                    }

                    // 如果处于ScrollView滚动状态，直接调用ScrollView自身滚动
                    if((!isOnBottom() && overScrollDistance > 0) || (!isOnTop() && overScrollDistance < 0)){
                        mContentLayout.smoothScrollToNormal();
                        overScrollDistance = 0;
                        break;
                    }

                    if(overScrollDistance * deltaY > 0){
                        deltaY = (int) (deltaY * ELASTICITY_COEFFICIENT);
                    }

                    if(overScrollDistance == 0){
                        deltaY = (int) (deltaY * ELASTICITY_COEFFICIENT * 0.5f);
                    }

                    if(overScrollDistance == 0 && deltaY == 0){
                        break;
                    }

                    //检测最终滚动距离，最大为20
                    if(Math.abs(deltaY) > 20){
                        deltaY = deltaY > 0 ? 20 : -20;
                    }

                    // 记录滚动总距离
                    overScrollDistance += deltaY;

                    if(isOnTop() && overScrollDistance > 0 && !isOnBottom()){
                        overScrollDistance = 0;
                        break;
                    }

                    if(isOnBottom() && overScrollDistance < 0 && !isOnTop()){
                        overScrollDistance = 0;
                        break;
                    }

                    // 滚动视图
                    mContentLayout.smoothScrollBy(0, deltaY);

                    if(mOverScrollTinyListener != null){
                        mOverScrollTinyListener.scrollDistance(deltaY, overScrollDistance);
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                mContentLayout.smoothScrollToNormal();
                overScrollTrigger();
                // 重置滑动总距离
                overScrollDistance = 0;
                // 重置标记
                isRecord = false;
                // 重置手指触摸id
                mActivePointerId = INVALID_POINTER;
                break;

            default:
                break;
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 功能描述: 防止出现pointerIndex out of range异常<br>
     *
     * @param ev
     */
    private void onSecondaryPointerUp(MotionEvent ev) {
        final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
        final int pointerId = ev.getPointerId(pointerIndex);
        if (pointerId == mActivePointerId) {
            // This was our active pointer going up. Choose a new
            // active pointer and adjust accordingly.
            // TODO: Make this decision more intelligent.
            final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
            mLastMotionY = (int) ev.getY(newPointerIndex);
            mActivePointerId = ev.getPointerId(newPointerIndex);
        }

    }

    public boolean isOverScrolled() {
        return isOnTop() || isOnBottom();
    }

    private boolean isOnTop(){
        return getScrollY() == 0;
    }

    private boolean isOnBottom(){
        return getScrollY() + getHeight() == mContentLayout.getHeight();
    }

    /**
     * 功能描述:初始化滚动视图 <br>
     * <br>
     * 将滚动视图添加到ScrollView作为子视图
     */
    private void initOverScrollLayout() {
        //必须设置为true,否则添加子视图时高度不会填充到整个ScrollView的高度
        setFillViewport(true);
        if(mContentLayout == null){
            // 获取ScrollView的子视图
            View child = getChildAt(0);
            // 初始化弹性滚动视图
            mContentLayout = new ElasticScrollViewLayout(getContext());
            // 移除ScrollView所有视图
            this.removeAllViews();
            // 将原先ScrollView子视图加入到弹性滚动视图中
            mContentLayout.addView(child);
            // 添加弹性滚动视图，作为ScrollView子视图
            this.addView(mContentLayout,new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

        }
//		mIsUseOverScroll = true;
    }

    /**
     * 功能描述:设置是否可以弹性滚动 <br>
     *
     * @param isOverScroll
     */
    public void setOverScroll(boolean isOverScroll){
        mIsUseOverScroll = isOverScroll;
    }

    /**
     * 功能描述: 设置是否使用惯性<br>
     *
     * @param isInertance
     */
    public void setUseInertance(boolean isInertance){
        mIsUseInertance = isInertance;
    }

    @Override
    protected void onAttachedToWindow() {
        initOverScrollLayout();
        super.onAttachedToWindow();
    }

    /**
     * 功能描述: 获取弹性状态<br>
     *
     * @return
     */
    public int getScrollState(){
        invalidateState();
        return overScrollSate;
    }

    /**
     * 功能描述: 刷新弹性滚动状态<br>
     */
    private void invalidateState(){

        if(mContentLayout.getScrollerCurrY() == 0){
            overScrollSate =  NO_OVERSCROLL_STATE;
        }

        if(mContentLayout.getScrollerCurrY() < 0){
            overScrollSate =  TOP_OVERSCROLL_STATE;
        }

        if(mContentLayout.getScrollerCurrY() > 0){
            overScrollSate =  BOTTOM_OVERSCROLL_STATE;
        }
    }

    @Override
    protected boolean overScrollBy(int deltaX, int deltaY, int scrollX,
                                   int scrollY, int scrollRangeX, int scrollRangeY,
                                   int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
//		Log.v("test", "deltaY "+deltaY+"   scrollY "+scrollY);
        return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX,
                scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent);
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        if(mScrollListener != null && overScrollDistance == 0){
            mScrollListener.onScroll(l, t, oldl, oldt);
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX,
                                  boolean clampedY) {
        if(mIsUseInertance && !isInertance && scrollY != 0){
            isInertance = true;
        }
        if(clampedY && !isOnTouch && isInertance){
            mContentLayout.smoothScrollBy(0, inertanceY);
            mContentLayout.smoothScrollToNormal();
            inertanceY = 0;
        }
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
    }

    /**
     * 功能描述: 设置OverScroll滚动监听器<br>
     *
     * @param listener
     */
    public void setOverScrollListener(OverScrollListener listener){
        mOverScrollListener = listener;
    }

    /**
     * 功能描述: 设置OverScroll滚动监听器<br>
     *
     * @param listener
     */
    public void setOverScrollTinyListener(OverScrollTinyListener listener){
        mOverScrollTinyListener = listener;
    }

    /**
     * 功能描述: 设置Scroll滚动监听器<br>
     *
     * @param listener
     */
    public void setOnScrollListener(OnScrollListener listener){
        mScrollListener = listener;
    }

    /**
     * 设置OverScrollListener出发阀值
     * @param height
     */
    public void setOverScrollTrigger(int height){
        if(height >= 30){
            mOverScrollTrigger = height;
        }
    }

    private void overScrollTrigger(){
        if(mOverScrollListener == null){
            return;
        }

        if(overScrollDistance > mOverScrollTrigger && isOnBottom()){
            mOverScrollListener.footerScroll();
        }

        if(overScrollDistance < -mOverScrollTrigger && isOnTop()){
            mOverScrollListener.headerScroll();
        }

    }

    public void setQuickScroll(boolean isEnable){
        mIsBanQuickScroll = !isEnable;
    }

    @Override
    public void computeScroll() {
        if(!mIsBanQuickScroll){
            super.computeScroll();
        }
    }

    /**
     * 获取ScrollView可滚动高度
     * @return
     */
    public int getScrollHeight(){
        return mContentLayout.getHeight() - getHeight();
    }

    @Override
    public void fling(int velocityY) {
        inertanceY = 50 * velocityY / 5000;
        super.fling(velocityY);
    }


    /**
     * 当OverScroll超出一定值时，调用此监听
     *
     * @author King
     * @since 2014-4-9 下午4:36:29
     */
    public interface OverScrollListener {

        /**
         * 顶部
         */
        void headerScroll();

        /**
         * 底部
         */
        void footerScroll();

    }

    /**
     * 每当OverScroll时，都能触发的监听
     * @author King
     * @since 2014-4-9 下午4:39:06
     */
    public interface OverScrollTinyListener{

        /**
         * 滚动距离
         * @param tinyDistance 当前滚动的细小距离
         * @param totalDistance 滚动的总距离
         */
        void scrollDistance(int tinyDistance, int totalDistance);

        /**
         * 滚动松开
         */
        void scrollLoosen();
    }

    /**
     * 普通滚动监听器<br>
     * overScroll距离为0切无惯性时调用
     *
     * @author king
     *
     */
    public interface OnScrollListener{
        void onScroll(int l, int t, int oldl, int oldt);
    }
}
